﻿using Juli.Mes.Mqtt.Etos;
using Microsoft.Extensions.Logging;
using MQTTnet.Server;
using MQTTnet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.EventBus.Distributed;
using Juli.Mes.Mqtt.Topics;
using Volo.Abp.EventBus.Local;

namespace Juli.Mes.Mqtt
{
    [ExposeServices(typeof(IMqttPublishingService), typeof(IMqttService))]
    public class MqttPublishingService : MqttServiceBase, IMqttPublishingService, ISingletonDependency
    {
        private readonly ILogger<MqttPublishingService> _logger;
        private readonly ILocalEventBus _localEventBus;

        public MqttPublishingService(
            ILogger<MqttPublishingService> logger,
            ILocalEventBus localEventBus)
           : base()
        {
            _logger = logger;
            _localEventBus = localEventBus;
        }

        public override void ConfigureMqttServer(MqttServer mqttServer)
        {
            base.ConfigureMqttServer(mqttServer);

            MqttServer.InterceptingPublishAsync += InterceptingPublishHandlerAsync;
        }

        private async Task InterceptingPublishHandlerAsync(InterceptingPublishEventArgs eventArgs)
        {
            var topic = eventArgs.ApplicationMessage.Topic;

            _logger.LogDebug($"'{eventArgs.ClientId}' published '{eventArgs.ApplicationMessage.Topic}' > '{Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload ?? new byte[0])}'");

            if (eventArgs.ClientId == null ) { }

            #region TODO：根据ClientId，用户等判断是能发布这种主题 等具体的业务逻辑，慢慢规划

            ///// TDOD
            //if (topic == "not_allowed_topic") // TODO:
            //{
            //    eventArgs.ProcessPublish = false;
            //    eventArgs.CloseConnection = true;
            //}

            //if (MqttTopicFilterComparer.Compare(eventArgs.ApplicationMessage.Topic, "/myTopic/WithTimestamp/#") == MqttTopicFilterCompareResult.IsMatch)
            //{
            //    // Replace the payload with the timestamp. But also extending a JSON 
            //    // based payload with the timestamp is a suitable use case.
            //    eventArgs.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O"));
            //}


            //// TODO:根据ClientId, 判断是否有权限去发布主题
            //if (MqttTopicHelper.IsSystemTopic(topic))
            //{
            //    if (!MqttTopicHelper.IsBrokerItself(eventArgs.ClientId))
            //    {
            //        // 客户端要发布系统主题，不接受，而是由系统执行系统主题的发布
            //        // await _mqttInternalService.ExecuteSystemCommandAsync(context);
            //        eventArgs.ProcessPublish = false;
            //        return;
            //    }
            //}
            //else
            //{
            //    if (!eventArgs.SessionItems.Contains(topic))
            //    {
            //        var payloadString = Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload);
            //        eventArgs.SessionItems.Add(eventArgs.ApplicationMessage.Topic, eventArgs.ApplicationMessage.Payload);
            //    }
            //    else
            //    {
            //        var retainPayload = (byte[])eventArgs.SessionItems[eventArgs.ApplicationMessage.Topic];
            //        if (!retainPayload.SequenceEqual(eventArgs.ApplicationMessage.Payload))
            //        {
            //        }
            //    }
            //}

            //if (eventArgs.ProcessPublish)
            //{
            //    await _distributedEventBus.PublishAsync(
            //       new ClientPublishTopicEto
            //       {
            //           ClientId = eventArgs.ClientId,
            //           Topic = eventArgs.ApplicationMessage.Topic,
            //           Payload = eventArgs.ApplicationMessage.Payload
            //       }
            //    );
            //}
            if (!MqttTopicHelper.IsBrokerItself(eventArgs.ClientId))
            {
                await _localEventBus.PublishAsync(new ClientPublishTelemetryEto
                {
                    ClientId = eventArgs.ClientId,
                    Topic = eventArgs.ApplicationMessage.Topic,
                    Payload = Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload)
                });
            }
            #endregion
        }
    }
}
